home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DS-CD ROM 2 1993 August
/
DS CD-ROM 2.Ausgabe (August 1993).iso
/
programm
/
ds0257
/
doc.exe
/
BHEAP.DOC
< prev
next >
Wrap
Text File
|
1992-02-21
|
25KB
|
562 lines
─────────────────────────────────────────────────────────────────────────────
Dokumentation zur Datei: BHEAP.INC
─────────────────────────────────────────────────────────────────────────────
BHEAP.INC - Routinen zur Verwaltung eines BasedHeaps
(für den Assembler A86)
(c) Bernd Schemmer 1992
Letzter Update: 21.02.1992
■ Beschreibung:
---------------
BHEAP.INC stellt Routinen zur Verwaltung eines BasedHeaps zur Verfügung.
Ein BasedHeap ist ein Heap (oder auf deutsch: eine Halde), der maximal
ein Segment (= 65.535 Byte) groß sein kann und nur mit Offset-Werten für
die Zeiger arbeitet.
Die minimale Größe für den BasedHeap ist ein Kilobyte (1.024 Byte).
Jeder Speicherblock auf dem BasedHeap belegt immer ein Vielfaches von
4 Byte plus 4 Byte zur Verwaltung des Blocks. Die maximale Länge eines
Blocks ist gleich dem maximalen freien Platz auf dem BasedHeap.
Es ist auch ein sequentielles Durchlaufen der Blöcke auf dem BasedHeap,
in beliebiger Richtung und ab einem beliebigen Block, möglich.
Das Vergrößern oder Verkleinern des BasedHeaps ist ebenfalls jederzeit
möglich.
Der BasedHeap wird von unten nach oben belegt, wobei, falls erwünscht,
immer zuerst die Löcher im belegten Teil wieder belegt werden. Die
Behandlung der freien Blöcke, will sagen: Zusammenfassen von freie
Blöcken oder nicht, ist ebenfalls variabel.
Die freien Blöcke werden über eine Freiblock-Kette verwaltet. Die
Freiblock-Kette wird mit einem stack-artigen Algorithmus verwaltet,
d.h. freie Blöcke werden immer am Anfang der Kette eingefügt und die
Suche nach freien Blöcken beginnt auch immer am Anfang der Kette.
Die maximal mögliche Anzahl von Elementen auf dem BasedHeap kann bei
Elementen mit gleicher Länge nach folgender Formel berechnet werden:
n = (HeapLength - 16) DIV ( BlockLength + 4)
mit:
HeapLength = Größe des Heaps
(Parameter der Routine 'InitBHeap', abgerundet
auf die nächste 4-Byte-Grenze)
BlockLength = Größe der zu belegenden Blöcke auf dem Heap
Der BasedHeap ist folgendermaßen aufgebaut:
BasedHeapSegment:0 n Byte Verwaltungsdaten für den BasedHeap
BasedHeapSegment:n 4 Byte für den Control-Block des 1. Blocks
auf dem BasedHeap
BasedHeapSegment:n+4 m1 Byte für den 1. Block auf dem BasedHeap
BasedHeapSegment:n+4+m1 4 Byte für den Control-Block des 2. Blocks
auf dem BasedHeap
BasedHeapSegment:n+4+m1+4 m2 Byte für den 2. Block auf dem BasedHeap
...
BasedHeapSegment:z 4 Byte für den Control-Block des folgenden
Blocks
BasedHeapSegment:z+4 mm Byte für den letzen Block auf dem
BasedHeap
Hinweis: Freie Blöcke auf dem BasedHeap dürfen auf keinen Fall
vom Programm verändert werden, da diese von den Routinen
zur Verwaltung der Freiblock-Kette verwendet werden.
Dem Nachteil dieses Heap-Konzepts, die Begrenzung des Heaps auf
maximal ein Segment, stehen mehrere Vorteile gegenüber:
1. Der Overhead an Speicherplatz für die Verwaltung des Heaps ist
mit 4 Byte pro Block und 16 Byte für den Header minimal.
2. Die gesamte Verwaltung arbeitet mit relativen Offsets. D.h. es
ist möglich, den BasedHeap in einem Programm zu belegen, diesen
vor dem Programmende in eine Datei zu sichern und später, z.B.
nach einem erneuten Programmstart, den gesicherten BasedHeap
neu zu laden und damit weiter zu arbeiten.
Die Segment-Adresse des BasedHeaps ist dabei völlig belanglos.
(Hinweis: Es muß nur der belegte Teil des BasedHeaps gesichert
werden. Der Speicherblock für den BasedHeap muß aber
immer die gleiche Größe haben!)
3. Da die Adress-Berechnungen in den Routinen zur Verwaltung des
BasedHeaps und in den Routinen, die den BasedHeap nutzen, nur
mit Offsets durchgeführt werden, ist die Geschwindigkeit auch
relativ hoch. (Nebenbei bemerkt: Ein weiterer Steigerung der
Geschwindigkeit konnte durch die Verwendung von zwei doppelt-
verketteten Listen zur Verwaltung der Blöcke erreicht werden.)
4. Die Routinen können mit mehreren BasedHeaps gleichzeitig arbeiten,
da alle Variablen zur Verwaltung des BasedHeaps auf den BasedHeap
eingerichtet werden.
Dadurch kann ein Programm z.B. für verschiedene Datentypen
verschiedene BasedHeaps anlegen. Falls ein BasedHeap nur für
Datentypen mit gleicher Länge benutzt wird, ist gewährleistet,
daß die beim Löschen von Elementen entstehenden Löcher immer
wieder vollständig belegt werden können und somit der Verschnitt
minimiert wird.
■ Variablen:
------------
BHeapSeg - Wort, Segment des aktuellen BasedHeaps
Alle Routinen (außer InitBHeap) definieren einen zusätzlichen
Einsprungpunkt 'name_A'. (z.B. für 'GetBHeapMem' ist dies
'GetBHeapMem_A'). Falls die Routinen über diesen Einsprungpunkt
aufgerufen werden, arbeiten sie auf dem BasedHeap, dessen
Segment in dieser Variable gespeichert ist. (Der Wert des
Registers ES beim Aufruf ist in diesen Fall ohne Bedeutung,
das Register ES wird aber NICHT gesichert! Die Variable muß
in diesem Fall vorher auf einen korrekten Wert gesetzt worden
sein! (direkt oder durch den Aufruf von 'InitBHeap')
Falls die Routinen über den normalen Einsprungpunkt aufgerufen
werden, wird diese Variable weder genutzt noch verändert.
BHeapSeg:[BHeapFlags] - Byte, Flags des BasedHeaps
Aufbau des Flag-Bytes:
Bit | Bedeutung
------+-------------------------------------------------------
0 | Bit = 0 ->> Bei der Belegung von neuen Blöcken
| zuerst die Löcher im schon belegten
| Teil berücksichtigen.
| Bit = 1 ->> Bei der Belegung von neuen Blöcken
| zuerst versuchen, den Block hinter den
| schon belegten Blöcken anzulegen.
|
1 | Bit = 0 ->> Bei der Freigabe von Blöcken aufeinander
| folgende freie Blöcke sofort nach der
| Freigabe zusammenfügen.
| Bit = 1 ->> Aufeinander folgende freie Blöcke nach der
| Freigabe nicht zusammenfügen. Dies ist
| z.B. sinnvoll, falls alle Elemente auf dem
| BasedHeap die gleiche Länge haben.
|
2 - 7 | reserviert, sollten 0 sein
|
Die Flags werden von der Routine 'InitBHeap' mit 0 vorbelegt.
Die Routine 'RepairBHeap' setzt, falls eine Reparatur durch-
geführt wird, die Flags ebenfalls auf 0.
Die Flags können zu beliebigen Zeitpunkten geändert werden.
BHeapSeg:[BHeapUserData1] - Wort, für Benutzerzwecke reserviert
BHeapSeg:[BHeapUserData2] - Wort, für Benutzerzwecke reserviert
An den Offsets BHeapUserData1 und BHeapUserData2 im Header
des BasedHeaps sind jeweils 2 Byte (= 1 Wort) für Daten des
Programms reserviert. Diese beiden Wörter werden von den
Routinen zur Verwaltung des BasedHeaps weder gelesen noch
verändert (also auch nicht mit einem bestimmten Wert initi-
alisiert).
(BHeapUserData1 und BHeapUserData2 sind über 'dw' definiert)
Alle anderen Variablen zur Verwaltung des BasedHeaps werden auf
dem BasedHeap angelegt und sollten von anderen Routinen weder
gelesen noch verändert werden!
■ Routinen:
-----------
InitBHeap - Initialisert (d.h. löscht) den BasedHeap
!! Alle weiteren Routinen können erst benutzt werden, falls !!
!! entweder 'InitBHeap' aufgerufen wurde oder der BasedHeap !!
!! anderweitig eingerichtet wurde (z.B. durch Lesen aus !!
!! einer Datei). !!
GetBHeapMem - Belegt einen Block auf dem BasedHeap
FreeBHeapMem - Gibt einen belegten Block wieder frei
ReleaseBHeapMem - Gibt alle Blöcke ab einem Block frei
GetBHeapBlockLength - Ermittelt die Länge eines Blocks
GetFirstBHeapBlock - Ermittelt den ersten Block
GetLastBHeapBlock - Ermittelt den letzten Block
GetNextBHeapBlock - Ermittelt den nächsten Block
GetPrevBHeapBlock - Ermittelt den vorherigen Block
GetBHeapMemAvail - Ermittelt den freien Speicherplatz und
die Länge des größten freien Blocks
GetMaxBHeapPointer - Ermittelt die Größe des belegten Teils des
BasedHeaps
ChangeBHeapSize - Vergrößert oder verkleinert den BasedHeap
ChainFreeBHeapBlocks - Faßt alle benachbarten freien Blöcke in
jeweils einen großen freien Block zusammen.
RepairBHeap - Repariert den BasedHeap
Der Aufruf der Routine 'RepairBHeap' ist notwendig, falls ein
Teil der Verwaltungsdaten des BasedHeaps überschrieben wurden.
In diesem Fall versucht 'RepairBHeap' den Fehler zu beseitigen
um eventuelle Datenverluste zu minimieren.
'RepairBHeap' sollte aufgerufen werden, falls eine Routine die
Fehlernummer für 'fataler Fehler' zurückliefert.
Falls 'RepairBHeap' selbst diesen Fehler zurückliefert, ist
eine Reparatur des BasedHeaps nicht mehr möglich!
'RepairBHeap' sollte auch aufgerufen werden, falls eine Routine
unerwarteterweise die Fehlernummer für 'kein korrekter Zeiger
angegeben' oder die Fehlernnumer für 'Fehler in der Kette der
freien Blöcke' zurückliefert. In diesen Fall kann 'RepairBHeap'
den Fehler fast in allen Fällen korrigieren, wobei bei einem
Einzelfehler (d.h. nur ein Control-Block ist defekt), maximal
3 Blöcke des BasedHeaps verloren gehen.
Die Routinen überprüfen immer, ob der Header des BasedHeaps verändert
wurde und, falls ein Zeiger angegeben ist, ob dieser korrekt ist.
Die Routinen benutzen das Register AX als Arbeitssregister.
Falls die Routinen über den Einsprungpunkt 'name_A' aufgerufen werden,
wird auch das Register ES verändert.
Hinweis: Da nicht alle verwendeten Namen und Bezeichner dieser Datei
dokumentiert sind, sollten bei Nutzung dieser Routinen in
den anderen Quelltexten keine Namen oder Bezeichner, die
die Zeichenkette 'BHeap' oder 'BH_' enthalten, verwendet
werden.
■ EQUs für die Flags des BasedHeaps
TryLastPtrFirst EQU 001h ; neue Blöcke zuerst hinter den belegten
; Blöcken anlegen (log. Operation: OR )
FreePtrFirst EQU 0FEh ; für neue Blöcke zuerst die Löcher belegen
; (logische Operation: AND)
BigFreeBlocks EQU 0FDh ; freie Blöcke sofort zusammenfassen
; (logische Operation: AND)
NoBigFreeBlocks EQU 002h ; freie Blöcke nicht zusammenfassen
; (logische Operation: OR)
■ Fehlernummern der Routinen
----------------------------
Alle Fehlernummern der Routinen haben das Format 80xx, wobei xx die
Nummer des eigentlichen Fehlers ist.
Name Nummer Bedeutung
----------------------------------------------------------------------
BHeapFatalError EQU 080FFh ; Fataler Fehler
; Der Header des BasedHeaps ist defekt.
; In diesem Fall sollte versucht werden,
; den Fehler durch die Routine 'Repair-
; BHeap' zu korrigieren (s.o.).
BHeapPointerError EQU 080FEh ; Der angegebene Zeiger zeigt NICHT auf
; einen BasedHeapBlock. Falls dieser
; Fehler auftritt, sollte ebenfalls
; versucht werden, den Fehler durch die
; Routine 'RepairBHeap' zu korrigieren
; (s.o.).
BHeapFPointerError EQU 080FDh ; Fehler in der Kette der freien Blöcke
; Falls dieser Fehler auftritt, kann er
; immer über die Routine 'RepairBHeap'
; behoben werden (s.o.).
BHeapLengthError EQU 080FCh ; Falsche Größe für den BasedHeap
; angegeben.
; Der Fehler wird nur von den Routinen
; 'InitBHeap' und 'ChangeBHeapSize'
; zurückgeliefert.
BHeapNoMoreBlocks EQU 08001h ; Keine weiteren Blöcke vorhanden
; Fehlernummer der Routinen 'GetNext-
; BHeapBlock' und 'GetPrevBHeapBlock'
; falls der letzte bzw. erste Block
; erreicht wurde.
BHeapFreeBLError EQU 08002h ; Freizugebender Block ist schon frei.
BHeapMemoryError EQU 08003h ; Ein Block mit der angeforderten Größe
; ist nicht mehr verfügbar.
BHeapRepaired EQU 08004h ; Fehlernummer der Routine 'RepairBHeap',
; falls die Reparatur geglückt ist.
----------------------------
ChainFreeBHeapBlocks
Funktion: Zusammenfaßen aller benachbarten freien Blöcke zu
jeweils einem großen freien Block
Eingabe: ES = Segment des BasedHeaps
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
ChangeBHeapSize
Funktion: Vergrößert oder verkleinert den BasedHeap
Eingabe: CX = neue Größe für den BasedHeap in Byte (incl. Header)
Falls CX = 0 ist, gibt die Routine nur die aktuelle
gesamte Größe des BasedHeaps im Register AX zurück
(incl. Header).
Es muß gelten: 1.024xD <= CX <= 65.535xD
und: CX >= belegter_Teil_des_BasedHeaps
Ausgabe: CF = 0 ->> okay
AX = neue Größe des BasedHeaps (incl. Header)
CF = 1 ->> Fehler
AX = Fehlernummer
Die Größe des BasedHeap wurde nicht verändert.
Bes.: Die neue Größe wird immer auf einen durch 4 teilbaren
Wert abgerundet.
Der BasedHeap kann nur soweit verkleinert werden, daß
keine belegten Blöcke verloren gehen.
Die eigentliche Änderung der Blockgröße (falls der Block
z.B. über DOS allociert wurde) muß die aufrufende Routine
in folgender Reihenfolge durchführen:
1. Verkleinern | 2. Vergrößern
-------------------------------+---------------------------
mov cx,Shorter_NewSize | mov cx,Bigger_NewSize
call ChangeBHeapSize_A | ; Speicherblock vergrößern
jc Fehler | call ChangeBHeapSize_A
; Speicherblock verkleinern | jc Fehler
----------------------------
InitBHeap
Funktion: Initialisiert (d.h. löscht) den gesamten BasedHeap
Eingabe: ES = Segment des BasedHeaps
Der BasedHeap beginnt immer mit dem Header am
Offset 0 im angegebenen Segment.
CX = Länge des BasedHeaps in Byte
(incl. Verwaltungsdaten)
Es muß gelten: 1.024xD <= CX <= 65.535xD
Ausgabe: CF = 0 ->> okay
AX = freier Speicher auf dem BasedHeap
Die Variable BHeapSeg wird gesetzt.
CF = 1 ->> Fehler
AX = Fehlernummer
Die Variable BHeapSeg wird nicht verändert.
Bes.: Der Speicherbereich für den BasedHeap muß vorher schon
allociert worden sein! Die angegebene Länge beinhaltet
auch die Kontroll-Strukturen (Header und Control-Blocks)
für den BasedHeap, d.h. der in AX zurückgegebene Wert
ist immer bis zu 23 Byte kleiner als der Wert in CX.
----------------------------
GetBHeapBlockLength
Funktion: Ermittelt die Länge eines Blocks
Eingabe: ES:BX -> Block
Ausgabe: CF = 0 ->> okay
CX = Länge des Blocks
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
GetFirstBHeapBlock
Funktion: Ermittelt den ersten Block auf dem BasedHeap
Eingabe: ES = Segment des BasedHeaps
Ausgabe: CF = 0 ->> okay
ES:BX -> erster Block auf dem BasedHeap
CX = Länge des Blocks
ZF = 1 ->> Block ist frei
Freie Blöcke dürfen NICHT verändert
werden!
ZF = 0 ->> Block ist belegt
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
GetNextBHeapBlock
Funktion: Ermittelt den nächsten Block auf dem BasedHeap
Eingabe: ES:BX -> BasedHeapBlock
Ausgabe: CF = 0 ->> okay
ES:BX -> nächster Block auf dem BasedHeap
CX = Länge des Blocks
ZF = 1 ->> Block ist frei
Freie Blöcke dürfen NICHT verändert
werden!
ZF = 0 ->> Block ist belegt
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
GetPrevBHeapBlock
Funktion: Ermittelt den vorherigen Block auf dem BasedHeap
Eingabe: ES:BX -> BasedHeapBlock
Ausgabe: CF = 0 ->> okay
ES:BX -> vorheriger Block auf dem BasedHeap
CX = Länge des Blocks
ZF = 1 ->> Block ist frei
Freie Blöcke dürfen NICHT verändert
werden!
ZF = 0 ->> Block ist belegt
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
GetLastBHeapBlock
Funktion: Ermittelt den letzten Block auf dem BasedHeap
Eingabe: ES = Segment des BasedHeaps
Ausgabe: CF = 0 ->> Okay
ES:BX -> letzter Block auf dem BasedHeap
CX = Länge des Blocks
ZF = 1 ->> Block ist frei
Freie Blöcke dürfen NICHT verändert
werden!
ZF = 0 ->> Block ist belegt
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
GetMaxBHeapPointer
Funktion: Ermittelt die Länge des benutzten Teils des BasedHeaps
Eingabe: ES = Segment des BasedHeaps
Ausgabe: CF = 0 ->> okay
AX = Länge des benutzten Teils des BasedHeaps
CF = 1 ->> Fehler
AX = Fehlernummer
Bes.: Falls der BasedHeap in eine Datei gesichert werden soll,
müssen nur die ersten n Byte gesichert werden, wobei
n der von dieser Routine bei erfolgreicher Ausführung
im Register AX zurückgegebene Wert ist.
----------------------------
GetBHeapMemAvail
Funktion: Ermittelt den freien Speicherplatz auf dem BasedHeap
Eingabe: ES = Segment des BasedHeaps
Ausgabe: CF = 0 ->> okay
CX = Größe des größten freien Blocks in Byte
DX = Gesamt-Größe des freien Speichers in Byte
AX = Anzahl der freien Blöcke
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
ReleaseBHeapMem
Funktion: Freigabe aller Speicherblöcke ab einem vorgegebenen
Speicherblock
Eingabe: ES:BX -> erster freizugebender Speicherblock
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Hinweis: Falls der gesamte BasedHeap gelöscht werden soll, sollte
die Routine 'InitBHeap' verwendet werden.
Der erste freizugebende Block kann, genau wie die folgenden
Blöcke auch, ein freier oder ein belegter Block sein.
Bes.: Freie Blöcke dürfen NICHT verändert werden!
Alle freigegebenen Blöcke werden, unabhängig vom Flag-Bit,
zu einem Block zusammen gefaßt.
----------------------------
FreeBHeapMem
Funktion: Freigabe eines Blocks auf dem BasedHeap
Eingabe: ES:BX -> freizugebender Block
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Bes.: Freie Blöcke dürfen NICHT verändert werden!
----------------------------
GetBHeapMem
Funktion: Belegen eines Blocks auf dem BasedHeap
Eingabe: ES = Segment des BasedHeaps
CX = Größe für den Block
Ausgabe: CF = 0 ->> okay
BX = Offset des Blocks
CX = Größe des belegten Blocks
CF = 1 ->> Fehler
AX = Fehlernummer
BX undefiniert
Bes.: Die angegebene Größe des Blocks wird immer auf einen durch 4
teilbaren Wert aufgerundet.
----------------------------
RepairBHeap
Funktion: Versucht, den BasedHeap zu reparieren
Dies ist nötig, falls ein Programm einen oder mehrere
Control-Blöcke oder den Header überschrieben hat.
(->> Fehler BHeapFatalError, BHeapPointerError oder
BHeapFPointerError)
Eingabe: ES = BasedHeap-Segment
Ausgabe: CF = 0 ->> BasedHeap ist in Ordnung
CF = 1 ->> BasedHeap war nicht in Ordnung
AX = Fehlernummer
möglich sind hier nur folgende Fehler:
AX = BHeapFatalError
->> BasedHeap kann nicht mehr repariert werden
AX = BHeapRepaired
->> BasedHeap wurde repariert
BX -> neuer belegter 'MüllBlock'
Dieser Block enthält aller wahr-
scheinlichkeit nur Datenmüll und
sollte freigegeben werden
Die Variable BHeapFlags wurde auf 0
gesetzt.
Bes.: Falls nur der Header einen korrigierbaren Fehler enthält,
gibt die Routine CF = 0 zurück.
Falls nur die Kette der freien Blöcke fehlerhaft war,
gibt die Routine ebenfalls CF = 0 zurück.